/*
 * Copyright (C) 2005-2006 Dmitri Maximovich <maxim@md.pp.ru>
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 */

/*
    cruisecontrol-2.4.1\main\src\net\sourceforge\cruisecontrol\ProjectState.java 
    
    public static final ProjectState QUEUED = new ProjectState(1, "queued", "in build queue");
    public static final ProjectState IDLE = new ProjectState(0, "idle", "idle");
    public static final ProjectState BOOTSTRAPPING = new ProjectState(2, "bootstrapping", "bootstrapping");
    public static final ProjectState MODIFICATIONSET = new ProjectState(3, "modificationset", "checking for modifications");
    public static final ProjectState BUILDING = new ProjectState(4, "building", "now building");
    public static final ProjectState MERGING_LOGS = new ProjectState(5, "merging", "merging accumulated log files");
    public static final ProjectState PUBLISHING = new ProjectState(6, "publishing", "publishing build results");
    public static final ProjectState PAUSED = new ProjectState(7, "paused", "paused");
    public static final ProjectState STOPPED = new ProjectState(8, "stopped", "stopped");
    public static final ProjectState WAITING = new ProjectState(9, "waiting", "waiting for next time to build");
*/

const ccProjectStatus = {
	"in build queue": "queued", 
	"checking for modifications": "checking", 
	"now building": "building", 
	"merging accumulated log files": "merging",
	"publishing build results": "publishing",
	"waiting for next time to build":"waiting"
};
const userAgent = "Mozilla/4.0 (compatible; Build Monitor; http://www.md.pp.ru/mozilla/cc/)";
var ccServers = null;

var CC = {
  log: function(msg) {
    dump((new Date).getTime()/1000+": "+msg+"\n");
  },

  onLoad: function() {
    var refreshInterval = parseInt(P.getString("refreshInterval", 30000));
    // force first 
    CC.timer();
    setTimeout(CC.timer, refreshInterval);
    this.initialized = true;
    CC.log("CC initialized. Refresh="+refreshInterval);
  },

  onOpenOptions: function() {
    window.open("chrome://cc/content/options.xul", "", "centerscreen,chrome,modal,dialog=yes");
  },

  timer: function() {
    if (!this.currentlyExecuting) {
        // TODO: don't need this check
		this.currentlyExecuting = true;
		try {
          CC.log("*** timer");
		  CC.refreshData();
		}
		catch(e) {
		  dump(e);
		} 
    }
    this.currentlyExecuting = false;
    setTimeout(CC.timer, 10000);
  },
  
  refreshData: function() {
    var servers = P.getServersAsArray();
    for(var i = 0; i < servers.length; i++) {
      var server = servers[i];
      CC.log("Server: "+server.name);
      // placeholder for projects
      server.projects = new Array();

      try {
	      var request = new XMLHttpRequest();
	      request.onload = function() { CC.handleServerResponse(server, request); };
	      request.onerror = function() { CC.handleServerError(server, request); };
	      request.open("GET", CC.getJmxUrl(server), false); // true == async
	      request.setRequestHeader("User-Agent", userAgent);
	      request.send(null);
	  }
	  catch (e) {
	    var msg = "Exception sending HTTP request. Check URL"
	    server.error = msg;
	    CC.log(msg);
	  }
    }
    // save
    ccServers = servers;
    // update toolbar
    T.updateToolbar(servers);
  },
  
  getJmxUrl: function(server, path, args) {
    var url = server.url;
    if (url.charAt(url.length-1) != '/') {
      url = url + '/';
    }
    if (path != null) {
      url = url+path;
    }
    url = url+"?template=identity";
    // optional arguments
	if (args != null) {
	  url = url+"&"+args; 
	}
    //CC.log("URL: ["+url+"]");
    return url;
  },
  
  handleServerResponse: function(server, request) {
	if (request.readyState != 4 || request.status != 200) {
		var msg = "Request failure. (HTTP status: "+request.status+")";
	    CC.log(msg);
	    server.error = msg;
		return;
	}
    //CC.log("Got response from "+server.name);
    var xmlParser = new DOMParser();
	var doc = xmlParser.parseFromString(request.responseText, 'text/xml');
	
	// Server:Element
	var root = doc.documentElement;
    if ((root.tagName == "parserError") || (root.namespaceURI == "http://www.mozilla.org/newlayout/xml/parsererror.xml")) {
	   var msg = "Response Parsing Error";
       CC.log(msg);
       server.error = msg;
       return;
    }
    var projectRoot = CC.getNodeByName(root, "CruiseControl Project");
    if (projectRoot == null) {
      var msg = "ProjectRoot not found in response";
      CC.log(msg);
      server.error = msg;
      return;
    }
    var projects = projectRoot.childNodes;
    for(var i = 0; i < projects.length; i++) {
      var project = projects.item(i); // Node
      var projectName = project.attributes.getNamedItem("objectname").value;
      CC.getProjectDetails(server, projectName);
    }
  },

  handleServerError: function(server, request) {
    CC.log(server.name+": Request failure. (HTTP status: "+request.status+")");
    server.error = "Request failure. (HTTP status: "+request.status+")";
  },
  
  getProjectDetails: function(server, projectName) {
    //CC.log("Fetching details for ["+projectName+"]");
    var request = new XMLHttpRequest();
    request.onload = function() { 
      CC.parseProjectDetails(server, request);
    };
    request.open("GET", CC.getJmxUrl(server, "mbean", "objectname="+escape(projectName)), false); // true == async
    request.setRequestHeader("User-Agent", userAgent);
    var response = request.send(null);
  },

  parseProjectDetails: function(server, request) {
	if (request.readyState != 4 || request.status != 200) {
	  var msg = "Request failure. (HTTP status: "+request.status+")";
	    CC.log(msg);
	    server.error = msg;
		return;
	}
    var xmlParser = new DOMParser();
	var doc = xmlParser.parseFromString(request.responseText, 'text/xml');
	
	// Server:Element
	var root = doc.documentElement;
    if ((root.tagName == "parserError") || (root.namespaceURI == "http://www.mozilla.org/newlayout/xml/parsererror.xml")) {
      var msg = "Response Parsing Error";
       CC.log(msg);
       server.error = msg;
       return;
    }

    //CC.log(request.responseText);
    var project = new Object();
    project.name = CC.getNodeByName(root, "ProjectName").attributes.getNamedItem("value").value;
	project.status = CC.convertStatus(CC.getNodeByName(root, "Status").attributes.getNamedItem("value").value);
	project.label = CC.getNodeByName(root, "Label").attributes.getNamedItem("value").value;
	// convert to Date from "yyyyMMddHHmmss"
	project.lastBuild = getDateFromFormat(CC.getNodeByName(root, "LastBuild").attributes.getNamedItem("value").value, "yyyyMMddHHmmss");
	project.lastSuccessfulBuild = getDateFromFormat(CC.getNodeByName(root, "LastSuccessfulBuild").attributes.getNamedItem("value").value, "yyyyMMddHHmmss");
	project.buildStartTime = getDateFromFormat(CC.getNodeByName(root, "BuildStartTime").attributes.getNamedItem("value").value, "yyyyMMddHHmmss");
	
	project.paused = (CC.getNodeByName(root, "Paused").attributes.getNamedItem("value").value == "true");
	project.buildInterval = parseInt(CC.getNodeByName(root, "BuildInterval").attributes.getNamedItem("value").value);
	
	// derived properties
	project.passed = (project.lastBuild == project.lastSuccessfulBuild);

	// add to projects array
    server.projects.push(project);
    
    CC.log("Project: "+project.name+" : "+project.status);
  },

  // get Node by value of attribute 'name'
  getNodeByName: function(root, name) {
    var nodes = root.childNodes;  // NodeList
    for(var i = 0; i < nodes.length; i++) {
      var node = nodes.item(i); // Node
      var attrs = node.attributes; // NamedNodeMap
      if (name == attrs.getNamedItem("name").value) {
		return node;      
      }
    }
    return null;
  },
  
  // substitute (shorten) status name
  convertStatus: function(name) {
  	var result = ccProjectStatus[name];
  	return result != null ? result : name;
  }

};

window.addEventListener("load", function(e) { CC.onLoad(e); }, false); 

